/*
 * svgcanvas.js -- <matsuzaki.takuya@gmail.com>
 * MIT Licensed.
 */

(function() {

var isMSIE = /*@cc_on!@*/false;
var XMLNS = 'http://www.w3.org/2000/svg';
var XLINK = 'http://www.w3.org/1999/xlink';
var SVGVER = '1.1';

(function() {
  if(isMSIE) {
    if(!document.namespaces['svg']) {
      var obj = document.createElement('object');
      obj.id = 'AdobeSVG';
      obj.classid = 'clsid:78156a80-c6a1-4bbf-8e6a-3cd390eeb4e2';
      document.getElementsByTagName('head')[0].appendChild(obj);
      document.namespaces.add('svg', XMLNS);
      document.namespaces('svg').doImport('#AdobeSVG');
    }
//     if(!document.namespaces['xlink']) {
//       document.namespaces.add('xlink', XLINK);
//     }
  }
})();

function DescriptionClass() {
  this.desc = function() {
    return this.appendChild(SVG.Desc.apply(this, arguments));
  }
  this.metadata = function() {
    return this.appendChild(SVG.Metadata.apply(this, arguments));
  }
  this.title_ = function() {
    return this.appendChild(SVG.Title.apply(this, arguments));
  }
}

function UseClass() {
  this.use = function() {
    return this.appendChild(SVG.Use.apply(this, arguments));
  }
}

function StructureClass() {
  this.svg = function() {
    return this.appendChild(SVG.apply(this, arguments));
  }
  this.g = function() {
    return this.appendChild(SVG.Group.apply(this, arguments));
  }
  this.defs = function() {
    return this.appendChild(SVG.Defs.apply(this, arguments));
  }
  this.symbol = function() {
    return this.appendChild(SVG.Symbol.apply(this, arguments));
  }
  this.mixin([UseClass]);
}

function ConditionalClass() {
  this.switch_ = function() {
    return this.appendChild(SVG.Switch.apply(this, arguments));
  }
}

function ImageClass() {
  this.image = function() {
    return this.appendChild(SVG.Image.apply(this, arguments));
  }
}

function StyleClass() {
  this.style_ = function() {
    return this.appendChild(SVG.Style.apply(this, arguments));
  }
}

function ShapeClass() {
  this.rect = function() {
    return this.appendChild(SVG.Rect.apply(this, arguments));
  }
  this.circle = function() {
    return this.appendChild(SVG.Circle.apply(this, arguments));
  }
  this.line = function() {
    return this.appendChild(SVG.Line.apply(this, arguments));
  }
  this.polyline = function() {
    return this.appendChild(SVG.Polyline.apply(this, arguments));
  }
  this.polygon = function() {
    return this.appendChild(SVG.Polygon.apply(this, arguments));
  }
  this.ellipse = function() {
    return this.appendChild(SVG.Ellipse.apply(this, arguments));
  }
  this.path = function() {
    return this.appendChild(SVG.Path.apply(this, arguments));
  }
}

function TextClass() {
  this.text = function() {
    return this.appendChild(SVG.Text.apply(this, arguments));
  }
  this.altGlyphDef = function() {
    return this.appendChild(SVG.AltGlyphDef.apply(this, arguments));
  }
}

function TextContentClass() {
  this.tspan = function() {
    return this.appendChild(SVG.Tspan.apply(this, arguments));
  }
  this.tref = function() {
    return this.appendChild(SVG.Tref.apply(this, arguments));
  }
  this.textPath = function() {
    return this.appendChild(SVG.TextPath.apply(this, arguments));
  }
  this.altGlyph = function() {
    return this.appendChild(SVG.AltGlyph.apply(this, arguments));
  }
}

function AltGlyphItem() {
  this.altGlyphItem = function() {
    return this.appendChild(SVG.AltGlyphItem.apply(this, arguments));
  }
}

function GlyphRef() {
  this.glyphRef = function() {
    return this.appendChild(SVG.GlyphRef.apply(this, arguments));
  }
}

function MarkerClass() {
  this.marker = function() {
    return this.appendChild(SVG.Marker.apply(this, arguments));
  }
}

function ColorProfileClass() {
  this.color_profile = function() {
    return this.appendChild(SVG.ColorProfile.apply(this, arguments));
  }
}

function GradientClass() {
  this.linearGradient = function() {
    return this.appendChild(SVG.LinearGradient.apply(this, arguments));
  }
  this.radialGradient = function() {
    return this.appendChild(SVG.RadialGradient.apply(this, arguments));
  }
}

function Stop() {
  this.stop = function() {
    return this.appendChild(SVG.Stop.apply(this, arguments));
  }
}

function PatternClass() {
  this.pattern = function() {
    return this.appendChild(SVG.Pattern.apply(this, arguments));
  }
}

function ClipClass() {
  this.clipPath = function() {
    return this.appendChild(SVG.ClipPath.apply(this, arguments));
  }
}

function MaskClass() {
  this.mask = function() {
    return this.appendChild(SVG.Mask.apply(this, arguments));
  }
}

function FilterClass() {
  this.filter = function() {
    return this.appendChild(SVG.Filter.apply(this, arguments));
  }
}

function FilterPrimitiveClass() {
  this.feBlend = function() {
    return this.appendChild(SVG.FeBlend.apply(this, arguments));
  }
  this.feFlood = function() {
    return this.appendChild(SVG.FeFlood.apply(this, arguments));
  }
  this.feColorMatrix = function() {
    return this.appendChild(SVG.FeColorMatrix.apply(this, arguments));
  }
  this.feComponentTransfer = function() {
    return this.appendChild(SVG.FeComponentTransfer.apply(this, arguments));
  }
  this.feComposite = function() {
    return this.appendChild(SVG.FeComposite.apply(this, arguments));
  }
  this.feConvolveMatrix = function() {
    return this.appendChild(SVG.FeConvolveMatrix.apply(this, arguments));
  }
  this.feDiffuseLighting = function() {
    return this.appendChild(SVG.FeDiffuseLighting.apply(this, arguments));
  }
  this.feDisplacementMap = function() {
    return this.appendChild(SVG.FeDisplacementMap.apply(this, arguments));
  }
  this.feGaussianBlur = function() {
    return this.appendChild(SVG.FeGaussianBlur.apply(this, arguments));
  }
  this.feImage = function() {
    return this.appendChild(SVG.FeImage.apply(this, arguments));
  }
  this.feMerge = function() {
    return this.appendChild(SVG.FeMerge.apply(this, arguments));
  }
  this.feMorphology = function() {
    return this.appendChild(SVG.FeMorphology.apply(this, arguments));
  }
  this.feOffset = function() {
    return this.appendChild(SVG.FeOffset.apply(this, arguments));
  }
  this.feSpecularLighting = function() {
    return this.appendChild(SVG.FeSpecularLighting.apply(this, arguments));
  }
  this.feDiffuseLighting = function() {
    return this.appendChild(SVG.FeDiffuseLighting.apply(this, arguments));
  }
  this.feTile = function() {
    return this.appendChild(SVG.FeTile.apply(this, arguments));
  }
  this.feTurbulence = function() {
    return this.appendChild(SVG.FeTurbulence.apply(this, arguments));
  }
}

function FeFuncRGBA() {
  this.feFuncR = function() {
    return this.appendChild(SVG.FeFuncR.apply(this, arguments));
  }
  this.feFuncG = function() {
    return this.appendChild(SVG.FeFuncG.apply(this, arguments));
  }
  this.feFuncB = function() {
    return this.appendChild(SVG.FeFuncB.apply(this, arguments));
  }
  this.feFuncA = function() {
    return this.appendChild(SVG.FeFuncA.apply(this, arguments));
  }
}

function FeMergeNode() {
  this.feMergeNode = function() {
    return this.appendChild(SVG.FeMergeNode.apply(this, arguments));
  }
}

function FeLight() {
  this.feDistantLight = function() {
    return this.appendChild(SVG.FeDistantLight.apply(this, arguments));
  }
  this.fePointLight = function() {
    return this.appendChild(SVG.FePointLight.apply(this, arguments));
  }
  this.feSpotLight = function() {
    return this.appendChild(SVG.FeSpotLight.apply(this, arguments));
  }
}

function CursorClass() {
  this.cursor = function() {
    return this.appendChild(SVG.Cursor.apply(this, arguments));
  }
}

function HyperlinkClass() {
  this.anchor = function() {
    return this.appendChild(SVG.Anchor.apply(this, arguments));
  }
}

function ViewClass() {
  this.view = function() {
    return this.appendChild(SVG.View.apply(this, arguments));
  }
}

function ScriptClass() {
  this.script = function() {
    return this.appendChild(SVG.Script.apply(this, arguments));
  }
}

function AnimationClass() {
  this.animate = function() {
    return this.appendChild(SVG.Animate.apply(this, arguments));
  }
  this.set = function() {
    return this.appendChild(SVG.Set.apply(this, arguments));
  }
  this.animateTransform = function() {
    return this.appendChild(SVG.AnimateTransform.apply(this, arguments));
  }
  this.animateMotion = function() {
    return this.appendChild(SVG.AnimateMotion.apply(this, arguments));
  }
  this.animateColor = function() {
    return this.appendChild(SVG.AnimateColor.apply(this, arguments));
  }
}

function Mpath() {
  this.mpath = function() {
    return this.appendChild(SVG.Mpath.apply(this, arguments));
  }
}

function FontClass() {
  this.font = function() { }
}

function ExtensibilityClass() {
  this.foreignObject = function() {
  }
}

function createSVGElement(tag, opt) {
  opt = opt || {};
  
  var e;
  if(!isMSIE) {
    e = document.createElementNS(XMLNS, tag);
    e._setAttribute = e.setAttribute;
    (function() {
      this.setAttribute = function() {
        if(/xlink:\w+/.test(arguments[0])) {
          this.setAttributeNS(XLINK, arguments[0], arguments[1]);
        } else {
          this._setAttribute(arguments[0], arguments[1]);
        }
      }
    }).call(e);
  } else {
    e = document.createElement('svg:'+tag);
  }
  
  e.setAttributes = function(opt) {
    for(attr in opt) {
      this.setAttribute(attr, opt[attr]);
    }
  }
  
  e.mixin = function(set) {
    for(var i=0; i<set.length; i++) {
      set[i].call(this);
    }
  }
  
  e.setAttributes(opt);
  return e;
}

SVG = function(container, width, height, opt) {
  opt = opt || {};
  opt['xmlns'] = XMLNS;
  opt['xmlns:xlink'] = XLINK;
  opt['version'] = SVGVER;
  opt['width'] = width;
  opt['height'] = height;
  
  var self = createSVGElement('svg', opt);
  self.mixin([
    DescriptionClass, StructureClass, ShapeClass, ImageClass, ViewClass,
    ConditionalClass, HyperlinkClass, TextClass, ScriptClass, StyleClass,
    MarkerClass, ClipClass, MaskClass, GradientClass, PatternClass,
    FilterClass, CursorClass, FontClass, AnimationClass, ColorProfileClass
  ]);
  if(container.constructor === String) {
    container = document.getElementById(container);
  }
  container.appendChild(self);
  return self;
}

SVG.Title = function(str, opt) {
  opt = opt || {};
  
  var self = createSVGElement('title', opt);
  self.appendChild(document.createTextNode(str));
  return self;
}

SVG.Desc = function(str, opt) {
  opt = opt || {};
  
  var self = createSVGElement('desc', opt);
  self.appendChild(document.createTextNode(str));
  return self;
}

SVG.Group = function(id, opt) {
  opt = opt || {};
  opt['id'] = id;
  
  var self = createSVGElement('g', opt);
  self.mixin([
    DescriptionClass, StructureClass, ShapeClass, ImageClass, ViewClass,
    ConditionalClass, HyperlinkClass, TextClass, ScriptClass, StyleClass,
    MarkerClass, ClipClass, MaskClass, GradientClass, PatternClass,
    FilterClass, CursorClass, FontClass, AnimationClass, ColorProfileClass
  ]);
  return self;
}

SVG.Defs = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('defs', opt);
  self.mixin([
    DescriptionClass, StructureClass, ShapeClass, ImageClass, ViewClass,
    ConditionalClass, HyperlinkClass, TextClass, ScriptClass, StyleClass,
    MarkerClass, ClipClass, MaskClass, GradientClass, PatternClass,
    FilterClass, CursorClass, FontClass, AnimationClass, ColorProfileClass
  ]);
  return self;
}

SVG.Metadata = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('metadata', opt);
  return self;
}

SVG.Symbol = function(id) {
  opt = opt || {};
  opt['id'] = id;
  
  var self = createSVGElement('symbol', opt);
  self.mixin([
    DescriptionClass, StructureClass, ShapeClass, ImageClass, ViewClass,
    ConditionalClass, HyperlinkClass, TextClass, ScriptClass, StyleClass,
    MarkerClass, ClipClass, MaskClass, GradientClass, PatternClass,
    FilterClass, CursorClass, FontClass, AnimationClass, ColorProfileClass
  ]);
  return self;
}

SVG.Use = function(uri, opt) {
  opt = opt || {};
  opt['xlink:href'] = uri;
  
  var self = createSVGElement('use', opt);
  self.mixin([DescriptionClass, AnimationClass]);
  return self;
}

SVG.Switch = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('switch', opt);
  self.mixin([
    DescriptionClass, ShapeClass, TextClass, StructureClass, ImageClass,
    HyperlinkClass, ExtensibilityClass, AnimationClass
  ]);
  return self;
}

SVG.Image = function(width, height, uri, opt) {
  opt = opt || {};
  opt['width'] = width;
  opt['height'] = height;
  opt['xlink:href'] = uri;
  
  var self = createSVGElement('image', opt);
  self.mixin([DescriptionClass, AnimationClass]);
  return self;
}

SVG.Style = function(str, opt) {
  opt = opt || {};
  opt['type'] = 'text/css';
  
  var self = createSVGElement('style', opt);
  self.appendChild('<![CDATA[' + document.createTextNode(str) + ']]');
  return self;
}

SVG.Path = function(opt) {
  opt = opt || {};
  opt['fill'] = opt['fill'] ? opt['fill'] : 'none';
  opt['stroke'] = opt['stroke'] ? opt['stroke'] : 'black';
  
  var self = createSVGElement('path', opt);
  
/*
  var _d = [];
  
  self.d = function(cmd) {
    _d.push(cmd);
    this.setAttribute('d', _d.join(' '));
  }
  
  self.undo = function() {
    _d.pop();
  }
  
  self.clear = function() {
    _d = [];
    this.setAttribute('d', _d.join(' '));
  }
*/
  var _d = '';
  self.d = function(cmd) {
    _d += cmd;
    this.setAttribute('d', _d);
  }
  
  self.M = function(x, y) {
    this.d('M' + x + ',' + y);
  }
  
  self.m = function(x, y) {
    this.d('m' + x + ',' + y);
  }
  
  self.L = function() {
    if(arguments[0].constructor === Array) {
      var xy = arguments[0].shift();
      this.L(xy[0], xy[1]);
      if(arguments[0].length) this.L(arguments[0]);
    } else {
      var x = arguments[0];
      var y = arguments[1];
      this.d('L' + x + ',' + y);
    }
  }
  
  self.l = function() {
    if(arguments[0].constructor === Array) {
      var xy = arguments[0].shift();
      this.L(xy[0], xy[1]);
      if(arguments[0].length) this.L(arguments[0]);
    } else {
      var x = arguments[0];
      var y = arguments[1];
      this.d('l' + x + ',' + y);
    }
  }
  
  self.H = function() {
    if(arguments[0].constructor === Array) {
      this.H(arguments[0].shift());
      if(arguments[0].length) this.H(arguments[0]);
    } else {
      var x = arguments[0];
      this.d('H ' + x);
    }
  }
  
  self.h = function() {
    if(arguments[0].constructor === Array) {
      this.h(arguments[0].shift());
      if(arguments[0].length) this.h(arguments[0]);
    } else {
      var x = arguments[0];
      this.d('h' + x);
    }
  }
  
  self.V = function() {
    if(arguments[0].constructor === Array) {
      this.V(arguments[0].shift());
      if(arguments[0].length) this.V(arguments[0]);
    } else {
      var y = arguments[0];
      this.d('V' + y);
    }
  }
  
  self.v = function() {
    if(arguments[0].constructor === Array) {
      this.v(arguments[0].shift());
      if(arguments[0].length) this.v(arguments[0]);
    } else {
      var y = arguments[0];
      this.d('v' + y);
    }
  }
  
  self.C = function() {
    if(arguments[0].constructor === Array) {
      var xy = arguments[0].shift();
      this.C(xy[0], xy[1], xy[2], xy[3], xy[4], xy[5]);
      if(arguments[0].length) this.C(arguments[0]);
    } else {
      var x1 = arguments[0];
      var y1 = arguments[1];
      var x2 = arguments[2];
      var y2 = arguments[3];
      var x  = arguments[4];
      var y  = arguments[5];
      this.d('C' + x1 + ',' + y1 + ' ' + x2 + ',' + y2 + ' ' + x + ',' + y);
    }
  }
  
  self.c = function() {
    if(arguments[0].constructor === Array) {
      var xy = arguments[0].shift();
      this.c(xy[0], xy[1], xy[2], xy[3], xy[4], xy[5]);
      if(arguments[0].length) this.c(arguments[0]);
    } else {
      var x1 = arguments[0];
      var y1 = arguments[1];
      var x2 = arguments[2];
      var y2 = arguments[3];
      var x  = arguments[4];
      var y  = arguments[5];
      this.d('c' + x1 + ',' + y1 + ' ' + x2 + ',' + y2 + ' ' + x + ',' + y);
    }
  }
  
  self.S = function() {
    if(arguments[0].constructor === Array) {
      var xy = arguments[0].shift();
      this.S(xy[0], xy[1], xy[2], xy[3]);
      if(arguments[0].length) this.S(arguments[0]);
    } else {
      var x2 = arguments[0];
      var y2 = arguments[1];
      var x  = arguments[2];
      var y  = arguments[3];
      this.d('S' + x2 + ',' + y2 + ' ' + x + ',' + y);
    }
  }
  
  self.s = function() {
    if(arguments[0].constructor === Array) {
      var xy = arguments[0].shift();
      this.s(xy[0], xy[1], xy[2], xy[3]);
      if(arguments[0].length) this.s(arguments[0]);
    } else {
      var x2 = arguments[0];
      var y2 = arguments[1];
      var x  = arguments[2];
      var y  = arguments[3];
      this.d('s' + x2 + ',' + y2 + ' ' + x + ',' + y);
    }
  }
  
  self.Q = function() {
    if(arguments[0].constructor === Array) {
      var xy = arguments[0].shift();
      this.Q(xy[0], xy[1], xy[2], xy[3]);
      if(arguments[0].length) this.Q(arguments[0]);
    } else {
      var x1 = arguments[0];
      var y1 = arguments[1];
      var x  = arguments[2];
      var y  = arguments[3];
      this.d('Q' + x1 + ',' + y1 + ' ' + x + ',' + y);
    }
  }
  
  self.q = function() {
    if(arguments[0].constructor === Array) {
      var xy = arguments[0].shift();
      this.q(xy[0], xy[1], xy[2], xy[3]);
      if(arguments[0].length) this.q(arguments[0]);
    } else {
      var x1 = arguments[0];
      var y1 = arguments[1];
      var x  = arguments[2];
      var y  = arguments[3];
      this.d('q' + x1 + ',' + y1 + ' ' + x + ',' + y);
    }
  }
  
  self.T = function() {
    if(arguments[0].constructor === Array) {
      var xy = arguments[0].shift();
      this.T(xy[0], xy[1]);
      if(arguments[0].length) this.T(arguments[0]);
    } else {
      var x = arguments[0];
      var y = arguments[1];
      this.d('T' + x + ',' + y);
    }
  }
  
  self.t = function() {
    if(arguments[0].constructor === Array) {
      var xy = arguments[0].shift();
      this.t(xy[0], xy[1]);
      if(arguments[0].length) this.t(arguments[0]);
    } else {
      var x = arguments[0];
      var y = arguments[1];
      this.d('t' + x + ',' + y);
    }
  }
  
  self.A = function() {
    if(arguments[0].constructor === Array) {
      var xy = arguments[0].shift();
      this.A(xy[0], xy[1], xy[2], xy[3], xy[4], xy[5], xy[6], xy[7]);
      if(arguments[0].length) this.A(arguments[0]);
    } else {
      var rx = arguments[0];
      var ry = arguments[1];
      var rotation = arguments[2];
      var arc_flag = arguments[3];
      var sweep_flag = arguments[4];
      var x = arguments[5];
      var y = arguments[6];
      this.d(
        'A' + rx + ',' + ry + ' ' + rotation + ' ' +
        arc_flag + ',' + sweep_flag + ' ' + x + ',' + y
      );
    }
  }
  
  self.a = function() {
    if(arguments[0].constructor === Array) {
      var xy = arguments[0].shift();
      this.a(xy[0], xy[1], xy[2], xy[3], xy[4], xy[5], xy[6], xy[7]);
      if(arguments[0].length) this.a(arguments[0]);
    } else {
      var rx = arguments[0];
      var ry = arguments[1];
      var rotation = arguments[2];
      var arc_flag = arguments[3];
      var sweep_flag = arguments[4];
      var x = arguments[5];
      var y = arguments[6];
      this.d(
        'a' + rx + ',' + ry + ' ' + rotation + ' ' +
        arc_flag + ',' + sweep_flag + ' ' + x + ',' + y
      );
    }
  }
  
  self.Z = function() {
    this.d('Z');
  }
  
  self.z = function() {
    this.d('z');
  }
  
  self.mixin([DescriptionClass, AnimationClass]);
  return self;
}

SVG.Rect = function(x, y, width, height, opt) {
  opt = opt || {};
  opt['x'] = x;
  opt['y'] = y;
  opt['width'] = width;
  opt['height'] = height;
  
  var self = createSVGElement('rect', opt);
  self.mixin([DescriptionClass, AnimationClass]);
  return self;
}

SVG.Circle = function(cx, cy, r, opt) {
  opt = opt || {};
  opt['cx'] = cx;
  opt['cy'] = cy;
  opt['r'] = r;
  
  var self = createSVGElement('circle', opt);
  self.mixin([DescriptionClass, AnimationClass]);
  return self;
}

SVG.Ellipse = function(cx, cy, rx, ry, opt) {
  opt = opt || {};
  opt['cx'] = cx;
  opt['cy'] = cy;
  opt['rx'] = rx;
  opt['ry'] = ry;
  
  var self = createSVGElement('ellipse', opt);
  self.mixin([DescriptionClass, AnimationClass]);
  return self;
}

SVG.Line = function(x1, y1, x2, y2, opt) {
  opt = opt || {};
  opt['stroke'] = opt['stroke'] ? opt['stroke'] : 'black';
  opt['x1'] = x1;
  opt['y1'] = y1;
  opt['x2'] = x2;
  opt['y2'] = y2;
  
  var self = createSVGElement('line', opt);
  self.mixin([DescriptionClass, AnimationClass]);
  return self;
}

SVG.Polyline = function(points, opt) {
  opt = opt || {};
  opt['fill'] = opt['fill'] ? opt['fill'] : 'none';
  opt['stroke'] = opt['stroke'] ? opt['stroke'] : 'black';
  opt['points'] = points;
  
  var self = createSVGElement('polyline', opt);
  self.mixin([DescriptionClass, AnimationClass]);
  return self;
}

SVG.Polygon = function(points, opt) {
  opt = opt || {};
  opt['fill'] = opt['fill'] ? opt['fill'] : 'none';
  opt['stroke'] = opt['stroke'] ? opt['stroke'] : 'black';
  opt['points'] = points;
  
  var self = createSVGElement('polygon', opt);
  self.mixin([DescriptionClass, AnimationClass]);
  return self;
}

SVG.Text = function(x, y, str, opt) {
  opt = opt || {};
  opt['fill'] = opt['fill'] ? opt['fill'] : 'black';
  opt['x'] = x;
  opt['y'] = y;
  
  var self = createSVGElement('text', opt);
  self.appendChild(document.createTextNode(str));
  self.mixin([
    DescriptionClass, TextContentClass, HyperlinkClass, AnimationClass
  ]);
  return self;
}

SVG.AltGlyphDef = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('altGlyphDef', opt);
  self.mixin([GlyphRef, AltGlyphItem]);
  return self;
}

SVG.Tspan = function(str, opt) {
  opt = opt || {};
  opt['fill'] = opt['fill'] ? opt['fill'] : 'black';
  
  var self = createSVGElement('tspan', opt);
  self.appendChild(document.createTextNode(str));
  self.mixin([
    DescriptionClass, TextContentClass, HyperlinkClass, AnimationClass
  ]);
  return self;
}

SVG.Tref = function(url, opt) {
  opt = opt || {};
  opt['xlink:href'] = uri;
  
  var self = createSVGElement('tref', opt);
  self.mixin([DescriptionClass, AnimationClass]);
  return self;
}

SVG.TextPath = function(str, url, opt) {
  opt = opt || {};
  opt['xlink:href'] = uri;
  
  var self = createSVGElement('textPath', opt);
  self.appendChild(document.createTextNode(str));
  self.mixin([
    DescriptionClass, TextContentClass, HyperlinkClass, AnimationClass
  ]);
  return self;
}

SVG.AltGlyph = function(str, opt) {
  opt = opt || {};
  
  var self = createSVGElement('altGlyph', opt);
  self.appendChild(document.createTextNode(str));
  return self;
}

SVG.AltGlyphItem = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('altGlyphItem', opt);
  self.mixin([GlyphRef]);
  return self;
}

SVG.GlyphRef = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('glyphRef', opt);
  return self;
}

SVG.Marker = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('marker', opt);
  self.mixin([
    DescriptionClass, StructureClass, ShapeClass, TextClass, ImageClass,
    ViewClass, ConditionalClass, HyperlinkClass, ScriptClass, ClipClass,
    MaskClass, GradientClass, PatternClass, FilterClass, CursorClass,
    FontClass, ColorProfileClass, AnimationClass
  ]);
  return self;
}

SVG.ColorProfile = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('color-profile', opt);
  self.mixin([DescriptionClass]);
  return self;
}

SVG.LinearGradient = function(id, opt) {
  opt = opt || {};
  opt['id'] = id;
  
  var self = createSVGElement('linearGradient', opt);
  self.mixin([DescriptionClass, AnimationClass, Stop]);
  return self;
}

SVG.RadialGradient = function(id, opt) {
  opt = opt || {};
  opt['id'] = id;
  
  var self = createSVGElement('radialGradient', opt);
  self.mixin([DescriptionClass, AnimationClass, Stop]);
  return self;
}

SVG.Stop = function(offset, color, opt) {
  opt = opt || {};
  opt['offset'] = offset;
  opt['stop-color'] = color;
  
  var self = createSVGElement('stop', opt);
  self.mixin([DescriptionClass, AnimationClass]);
  return self;
}

SVG.Pattern = function(id, opt) {
  opt = opt || {};
  opt['id'] = id;
  
  var self = createSVGElement('pattern', opt);
  self.mixin([
    DescriptionClass, StructureClass, ShapeClass, TextClass, ImageClass,
    HyperlinkClass, ScriptClass, StyleClass, ClipClass, MaskClass,
    GradientClass, PatternClass, FilterClass, CursorClass, FontClass,
    ColorProfileClass, AnimationClass
  ]);
  return self;
}

SVG.ClipPath = function(id, opt) {
  opt = opt || {};
  opt['id'] = id;
  
  var self = createSVGElement('clipPath', opt);
  self.mixin([
    DescriptionClass, ShapeClass, TextClass, UseClass, AnimationClass
  ]);
  return self;
}

SVG.Mask = function(id, opt) {
  opt = opt || {};
  opt['id'] = id;
  
  var self = createSVGElement('mask', opt);
  self.mixin([
    DescriptionClass, StructureClass, ShapeClass, TextClass, ImageClass,
    ScriptClass, StyleClass, MarkerClass, ClipClass, MaskClass, GradientClass,
    PatternClass, FilterClass, CursorClass, FontClass, ColorProfileClass,
    AnimationClass
  ]);
  return self;
}

SVG.Filter = function(id, opt) {
  opt = opt || {};
  opt['id'] = id;
  
  var self = createSVGElement('filter', opt);
  self.mixin([
    DescriptionClass, FilterPrimitiveClass, AnimationClass
  ]);
  return self;
}

SVG.FeBlend = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feBlend', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeColorMatrix = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feColorMatrix', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeComponentTransfer = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feComponentTransfer', opt);
  self.mixin([ FeFuncRGBA ]);
  return self;
}

SVG.FeComposite = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feComposite', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeConvolveMatrix = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feConvolveMatrix', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeDiffuseLighting = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feDiffuseLighting', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeDisplacementMap = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feDisplacementMap', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeGaussianBlur = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feGaussianBlur', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeImage = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feImage', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeMerge = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feMerge', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeMorphology = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feMorphology', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeOffset = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feOffset', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeSpecularLighting = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feSpecularLighting', opt);
  self.mixin([AnimationClass, FeLight]);
  return self;
}

SVG.FeDiffuseLighting = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feDiffuseLighting', opt);
  self.mixin([AnimationClass, FeLight]);
  return self;
}

SVG.FeTile = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feTile', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeTurbulence = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feTurbulence', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeFuncR = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feFuncR', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeFuncG = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feFuncG', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeFuncB = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feFuncB', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeFuncA = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feFuncA', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeMergeNode = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('feMergeNode', opt);
  self.mixin([FeMergeNode]);
  return self;
}

SVG.FeDistantLight = function(azimuth, elevation, opt) {
  opt = opt || {};
  opt['azimuth'] = azimuth;
  opt['elevation'] = elevation;
  
  var self = createSVGElement('feDistantLight', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FePointLight = function(x, y, z, opt) {
  opt = opt || {};
  opt['x'] = x;
  opt['y'] = y;
  opt['z'] = z;
  
  var self = createSVGElement('fePointLight', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.FeSpotLight = function(x, y, z, opt) {
  opt = opt || {};
  opt['x'] = x;
  opt['y'] = y;
  opt['z'] = z;
  
  var self = createSVGElement('feSpotLight', opt);
  self.mixin([AnimationClass]);
  return self;
}

SVG.Cursor = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('cursor', opt);
  self.mixin([DescriptionClass]);
  return self;
}

SVG.Anchor = function(uri, opt) {
  opt = opt || {};
  opt['xlink:href'] = uri;
  
  var self = createSVGElement('a', opt);
  self.mixin([
    StructureClass, DescriptionClass, ShapeClass, ImageClass,  ViewClass,
    ConditionalClass, HyperinkingClass, FontClass, ScriptClass, StyleClass,
    MarkerClass, ClipClass, MaskClass, GradientClass, PatternClass,
    FilterClass, CursorClass, AnimationClass, ColorProfileClass
  ]);
  return self;
}

SVG.Script = function(str, opt) {
  opt = opt || {};
  opt[type] = 'text/ecmascript';
  
  var self = createSVGElement('script', opt);
  self.appendChild('<![CDATA[' + document.createTextNode(str) + ']]');
  return self;
}

SVG.View = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('view', opt);
  self.mixin([DescriptionClass]);
  return self;
}

SVG.Animate = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('animate', opt);
  self.mixin([DescriptionClass]);
  return self;
}

SVG.Set = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('set', opt);
  self.mixin([DescriptionClass]);
  return self;
}

SVG.AnimateTransform = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('animateTransform', opt);
  self.mixin([DescriptionClass]);
  return self;
}

SVG.AnimateMotion = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('animateMotion', opt);
  self.mixin([DescriptionClass, Mpath]);
  return self;
}

SVG.AnimateColor = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('animateColor', opt);
  self.mixin([DescriptionClass]);
  return self;
}

SVG.Mpath = function(opt) {
  opt = opt || {};
  
  var self = createSVGElement('mpath', opt);
  self.mixin([DescriptionClass]);
  return self;
}

})();
